/* -------------------------------------------------------------------- */
#ifndef MINIMAKE_SHELL_H__
# define MINIMAKE_SHELL_H__

# include <sys/types.h>
# include <stdlib.h>
# include <stdio.h>

# include "mklib_parse-errors.h"

/* -------------------------------------------------------------------- */
typedef enum {
    RD_F_IN  = 0x00,
    RD_F_OUT = 0x01,
    RD_F_APP = 0x02,
} redir_file_kind_t;

typedef enum {
# define RD_M_FILE (0x00 << 2)
# define RD_M_DUP  (0x01 << 2)
# define RD_K_MSK  (0xff << 2)

    RD_INFILE  = RD_M_FILE | RD_F_IN,
    RD_OUTFILE = RD_M_FILE | RD_F_OUT,
    RD_APPFILE = RD_M_FILE | RD_F_APP,
    RD_DUP     = RD_M_DUP  | 0x00,
} redir_kind_t;

typedef struct {
    int fdin, fdout;
} redir_dup_t;

typedef union {
    char*       dt_tofile;
    redir_dup_t dt_dupfs;
} redir_data_t;

typedef struct {
    redir_kind_t kind;
    redir_data_t data;
} redir_t;

extern redir_t* redir_file_new(char *filename, redir_file_kind_t kind);
extern redir_t* redir_dup_new(int fdin, int fdout);
extern void redir_free(redir_t *the);

/* -------------------------------------------------------------------- */
typedef struct scommand {
    char    **argv  ;           /* NULL-terminated */
    redir_t **redirs;           /* NULL-terminated */
} scommand_t;

extern scommand_t* scommand_new(char **optargv, redir_t **optredirs);
extern void scommand_free(scommand_t *the);

/* -------------------------------------------------------------------- */
typedef struct {
    scommand_t **subcommands;   /* NULL-terminated */
} pcommand_t;

extern pcommand_t* pcommand_new(scommand_t **optsubcmds);
extern void pcommand_free(pcommand_t *the);

/* -------------------------------------------------------------------- */
typedef enum {
    CO_AND ,
    CO_OR  ,
    CO_SEQ ,
} cmd_op_t;

typedef struct command_s {
    int simple;

    union {
        struct {
            cmd_op_t kind;
            struct command_s *left;
            struct command_s *right;
        } node;

        pcommand_t *pcommand;
    };
} command_t;

extern command_t* command_new_singleton(pcommand_t *subcommand);
extern command_t* command_new_chain(cmd_op_t op, command_t *left, command_t *right);
extern void command_free(command_t *the);

/* -------------------------------------------------------------------- */
typedef struct {
    char  *name;
    char **value;               /* NULL-terminated */
} mk_var_t;

typedef struct {
    char       *target;
    char      **prereqs;        /* NULL-terminated */
    command_t **recipe;         /* NULL-terminated */
} mk_rule_t;

typedef struct {
    mk_var_t  **vars;           /* NULL-terminated */
    mk_rule_t **rules;          /* NULL-terminated */
} makefile_t;

extern void makefile_free(makefile_t *the);
extern makefile_t* makefile_parse(FILE *input);
extern makefile_t* makefile_parse_x(FILE *input, parse_error_t *cb);
extern void makefile_dump(const makefile_t *the);

#endif /* !MINIMAKE_SHELL_H__ */
